package com.mls.guardian.appst.common;

/**
 * Created by jl on 15/11/2.
 */

import com.mls.guardian.config.helper.ConfigPathManagr;
import com.mls.guardian.config.helper.JsonConfigHelper;
import com.mls.guardian.config.helper.PropConfigHelper;
import com.mls.guardian.dataobj.ProcessMessage;
import com.mls.guardian.em.ModuleType;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.jvmstat.monitor.*;
import sun.tools.jps.Arguments;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;

/**
 * Application to provide a listing of moni
 *
 * @author Brian Doherty
 * @since 1.5
 */
public class Jps {
    private static final Logger log = LoggerFactory.getLogger(Jps.class);

    /**
     * 获取jar最终存放目录
     *
     * @return
     */
    public static String getMoveDest() throws IOException {
        String rtn = "";
        PropConfigHelper propConfig = new PropConfigHelper();

        Map map = (Map) propConfig.parse(ConfigPathManagr.getConfigPath());
        rtn = (String) map.get("moveDest");

        return rtn;
    }

    /**
     * 获取tomcat配置目录
     *
     * @param projectName
     * @return
     * @throws IOException
     */
    public static List<String> getTomcatHome(String projectName) throws IOException {
        JsonConfigHelper jsonConfigHelper = new JsonConfigHelper();
        Map map = (Map) jsonConfigHelper.parse(ConfigPathManagr.getProjectConfigPath());

        Set keys = map.keySet();
        Iterator<String> its = keys.iterator();
        while (its.hasNext()) {
            String configProjectName = its.next();
            if (configProjectName.equals(projectName)) {
                Map projectMap = (Map) map.get(configProjectName);
                return (List<String>) projectMap.get("tomcatHome");
            }
        }

        return new ArrayList<String>();
    }

    /**
     * 获取jar模块(指定项目)
     *
     * @param projectName
     * @return
     * @throws IOException
     */
    public static List<String> getConfigModuleJar(String projectName) throws IOException {
        String moveDest = getMoveDest();
        List<String> list = new ArrayList<String>();
        JsonConfigHelper jsonConfigHelper = new JsonConfigHelper();

        Map map = (Map) jsonConfigHelper.parse(ConfigPathManagr.getProjectConfigPath());
        Set keys = map.keySet();
        Iterator<String> its = keys.iterator();
        while (its.hasNext()) {
            String tempProjectName = its.next();
            if (tempProjectName.equals(projectName)) {
                Map projectMap = (Map) map.get(tempProjectName);

                //jar模块
                List<String> modules = (List<String>) projectMap.get("jarModule");
                for (String item : modules) {
                    if (false == list.contains(item)) {
                        list.add(item);
                    }
                }
            }
        }

        return list;
    }

    public static List<String> getConfigModuleWeb(String projectName) throws IOException {
        String moveDest = getMoveDest();
        List<String> list = new ArrayList<String>();
        JsonConfigHelper jsonConfigHelper = new JsonConfigHelper();

        Map map = (Map) jsonConfigHelper.parse(ConfigPathManagr.getProjectConfigPath());
        Set keys = map.keySet();
        Iterator<String> its = keys.iterator();
        while (its.hasNext()) {
            String tempProjectName = its.next();
            if (tempProjectName.equals(projectName)) {
                Map projectMap = (Map) map.get(tempProjectName);
                //web模块
                List<String> modules = (List<String>) projectMap.get("webModule");
                for (String item : modules) {
                    if (false == list.contains(item)) {
                        list.add(item);
                    }
                }
            }
        }

        return list;
    }

    /**
     * 获取指定项目的进程信息
     *
     * @param projectName
     * @return
     * @throws IOException
     */
    public static List<ProcessMessage> getProcess(String projectName) throws Exception {
        List<ProcessMessage> listProcess = new ArrayList<ProcessMessage>();
        List<String> listConfigModuleJar = getConfigModuleJar(projectName);
        List<String> listConfigModuleWeb = getConfigModuleWeb(projectName);
        List<String> listConfigTomcat = getTomcatHome(projectName);

        List<VirtualMachineDescriptor> vms = VirtualMachine.list();
        for (VirtualMachineDescriptor item : vms) {
            if (item.displayName() != null && item.displayName().length() > 0) {
                if (item.displayName().indexOf("org.apache.catalina.startup.Bootstrap") > -1) {
                    //web
                    VirtualMachine vm = VirtualMachine.attach(item.id());
                    Properties props = vm.getSystemProperties();
                    //catalina.base:/home/service/tomcat8_r1
                    if (listConfigTomcat.contains(props.getProperty("catalina.base"))) {
                        for (String webModuleName : listConfigModuleWeb) {
                            listProcess.add(new ProcessMessage(item.id(), webModuleName, ModuleType.WEB, true));
                        }
                    }
                } else {
                    //jar
                    String itemName = filterProcessName(listConfigModuleJar, item.displayName());
                    if (itemName.length() > 0) {
                        listProcess.add(new ProcessMessage(item.id(), itemName, ModuleType.JAR, true));
                    }
                }
            }
        }

        return listProcess;
    }


    /**
     * 返回配置的模块名
     *
     * @param moduleList 配置文件模块名
     * @param longName   JPS输出信息
     * @return
     */
    private static String filterProcessName(List<String> moduleList, String longName) {
        String shortName = getJpsShortName(longName);
        //优先判断名称相等的
        if (moduleList.contains(shortName)) {
            return shortName;
        }

        //然后判断Jps shortName 包含模块名的
        for (String item : moduleList) {
            if (shortName.contains(item)) {
                return item;
            }
        }
        return "";
    }

    /**
     * 获取Jps返回的简短名称
     *
     * @param longName a/b/c/BaseComServer.jar
     * @return BaseComServer
     */
    private static String getJpsShortName(String longName) {
        int startIndex = longName.lastIndexOf(File.separator);
        int endIndex = longName.lastIndexOf(".");
        if (startIndex > 0 && endIndex > 0 && startIndex < endIndex && endIndex < longName.length()) {
            String shortName = longName.substring(startIndex + 1, endIndex);
            return shortName;
        }

        return longName;
    }

    private static Arguments arguments;

    public static void main(String[] args) {
        try {
            List<ProcessMessage> list = getProcess("wms");
            System.out.println("----wms----");
            for (ProcessMessage item : list) {
                System.out.println(item.getProcessId() + "----" + item.getModuleName());
            }

            System.out.println("----VirtualMachineDescriptor----");
            List<VirtualMachineDescriptor> vms = VirtualMachine.list();
            for (VirtualMachineDescriptor item : vms) {
                System.out.println(item.displayName());
                if (item.displayName().indexOf("Bootstrap") > -1) {
                    try {
                        VirtualMachine vm = VirtualMachine.attach(item.id());
                        Properties props = vm.getSystemProperties();

                        System.out.println("catalina.base:" + props.getProperty("catalina.base"));
                        for (Map.Entry<Object, Object> entry : props.entrySet()) {
                            //catalina.base:/home/service/tomcat8_r1
                            System.out.println("prop:" + entry.getKey().toString() + ":" + entry.getValue().toString());
                        }
                    } catch (AttachNotSupportedException e) {
                        e.printStackTrace();
                    }
                }
            }
            arguments = new Arguments(args);
        } catch (IllegalArgumentException e) {
            System.err.println(e.getMessage());
            Arguments.printUsage(System.err);
            return;
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (arguments.isHelp()) {
            Arguments.printUsage(System.out);
            System.exit(0);
        }

        try {
            HostIdentifier hostId = arguments.hostId();
            MonitoredHost monitoredHost =
                    MonitoredHost.getMonitoredHost(hostId);

            // get the set active JVMs on the specified host.
            Set jvms = monitoredHost.activeVms();

            for (Iterator j = jvms.iterator(); j.hasNext(); /* empty */) {
                StringBuilder output = new StringBuilder();
                Throwable lastError = null;

                int lvmid = ((Integer) j.next()).intValue();

                output.append(String.valueOf(lvmid));

                if (arguments.isQuiet()) {
                    System.out.println(output);
                    continue;
                }

                MonitoredVm vm = null;
                String vmidString = "//" + lvmid + "?mode=r";

                String errorString = null;

                try {
                    // Note: The VM associated with the current VM id may
                    // no longer be running so these queries may fail. We
                    // already added the VM id to the output stream above.
                    // If one of the queries fails, then we try to add a
                    // reasonable message to indicate that the requested
                    // info is not available.

                    errorString = " -- process information unavailable";
                    VmIdentifier id = new VmIdentifier(vmidString);
                    vm = monitoredHost.getMonitoredVm(id, 0);

                    errorString = " -- main class information unavailable";
                    output.append(" " + MonitoredVmUtil.mainClass(vm,
                            arguments.showLongPaths()));

                    if (arguments.showMainArgs()) {
                        errorString = " -- main args information unavailable";
                        String mainArgs = MonitoredVmUtil.mainArgs(vm);
                        if (mainArgs != null && mainArgs.length() > 0) {
                            output.append(" " + mainArgs);
                        }
                    }
                    if (arguments.showVmArgs()) {
                        errorString = " -- jvm args information unavailable";
                        String jvmArgs = MonitoredVmUtil.jvmArgs(vm);
                        if (jvmArgs != null && jvmArgs.length() > 0) {
                            output.append(" " + jvmArgs);
                        }
                    }
                    if (arguments.showVmFlags()) {
                        errorString = " -- jvm flags information unavailable";
                        String jvmFlags = MonitoredVmUtil.jvmFlags(vm);
                        if (jvmFlags != null && jvmFlags.length() > 0) {
                            output.append(" " + jvmFlags);
                        }
                    }

                    errorString = " -- detach failed";
                    monitoredHost.detach(vm);

                    System.out.println(output);

                    errorString = null;
                } catch (URISyntaxException e) {
                    // unexpected as vmidString is based on a validated hostid
                    lastError = e;
                    assert false;
                } catch (Exception e) {
                    lastError = e;
                } finally {
                    if (errorString != null) {
                         /*
                          * we ignore most exceptions, as there are race
                          * conditions where a JVM in 'jvms' may terminate
                          * before we get a chance to list its information.
                          * Other errors, such as access and I/O exceptions
                          * should stop us from iterating over the complete set.
                          */
                        output.append(errorString);
                        if (arguments.isDebug()) {
                            if ((lastError != null)
                                    && (lastError.getMessage() != null)) {
                                output.append("\n\t");
                                output.append(lastError.getMessage());
                            }
                        }
                        System.out.println(output);
                        if (arguments.printStackTrace()) {
                            lastError.printStackTrace();
                        }
                        continue;
                    }
                }
            }
        } catch (MonitorException e) {
            if (e.getMessage() != null) {
                System.err.println(e.getMessage());
            } else {
                Throwable cause = e.getCause();
                if ((cause != null) && (cause.getMessage() != null)) {
                    System.err.println(cause.getMessage());
                } else {
                    e.printStackTrace();
                }
            }
        }
    }
}